package icraf.carbon.model;

import icraf.carbon.core.CostBenefitUnit;
import icraf.carbon.core.Project;
import icraf.carbon.core.ProjectIO;
import icraf.carbon.core.Summary;
import icraf.carbon.core.Zone.DataType;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * @author DHarja
 * Manage the projects as the model outputs
 */
public class ModelProject {
	private ArrayList<Project> projectList = new ArrayList<Project>();
	private ArrayList<Summary> summaryList = new ArrayList<Summary>();
	private HashMap<CostBenefitUnit, ArrayList<Double>> emissionList = new HashMap<CostBenefitUnit, ArrayList<Double>>();
	

	public double getEmissionThreshold(int iteration, CostBenefitUnit cbu) {
		ArrayList<Double> e = emissionList.get(cbu);
		if(e != null)
			return e.get(iteration);
		return Double.NaN;
	}
	
	private Project mainProject;
	private int nIteration = 1;
	private String description = "Model";
	private String label = "Model";
	private double threshold = 5;
	
	public double getThreshold() {
		return threshold;
	}

	public void updateThreshold(double threshold) {
		this.threshold = threshold;
		emissionList.clear();
		ArrayList<CostBenefitUnit> cbuList = mainProject.getCostBenefitUnitList();
		for(CostBenefitUnit cbu: cbuList) {
			ArrayList<Double> e = emissionList.get(cbu);
			if(e == null) e = new ArrayList<Double>();
			for(Project p: projectList) {
				e.add(getEmissionThreshold(p, cbu));
			}
			emissionList.put(cbu, e);
		}
	}

	public int getIterationCount() {
		return nIteration;
	}

	private double getEmissionThreshold(Project p, CostBenefitUnit cbu) {
		p.updateDataArray();
		CostBenefitUnit cbuEqual = null;
		for(CostBenefitUnit cbuP: p.getCostBenefitUnitList()) {
			if(cbuP.getLabel().equals(cbu.getLabel())) {
				cbuEqual = cbuP;
				break;
			}
		}
		double  val = p.getTotalEmissionByCost(threshold, cbuEqual);
		return val;
	}
	
	public void updateSummary() {
		summaryList.clear();
		for(Project p: projectList) {
			summaryList.add(p.getSummary());
		}
	}
	
	private double progress = 1;
	
	public void runSimulationModel(int n) {
		progress = 0;
		this.nIteration = n;
		projectList.clear();
		summaryList.clear();
		
		Project p = ProjectIO.generateSibling(mainProject);
		p = AbacusModel.updateTransitionProbabilityMatrix(p);
		
		p = AbacusModel.copyMatrix(p, DataType.TPM_SCENARIO, DataType.TPM_SCENARIO_B);
		p = AbacusModel.copyMatrix(p, DataType.LANDUSE_SCENARIO, DataType.LANDUSE_SCENARIO_B);
		
		projectList.add(p);
		summaryList.add(p.getSummary());
		
		for(int i = 0; i < n; i++) {
			p = ProjectIO.generateSibling(p);
			p.setLabel(mainProject.getLabel()+" #"+(i+1));
			p = AbacusModel.runLanduseMatrixSimulation(p, 1, false);
			p = AbacusModel.updateTransitionProbabilityMatrix(p);
			
			p = AbacusModel.copyMatrix(p, DataType.TPM_SCENARIO, DataType.TPM_SCENARIO_B);
			p = AbacusModel.copyMatrix(p, DataType.LANDUSE_SCENARIO, DataType.LANDUSE_SCENARIO_B);
			
			projectList.add(p);
			summaryList.add(p.getSummary());
			progress = (i+1)/(float)n;
		}
		updateThreshold(threshold);
		progress = 1;
	}
	
	public void runSimulationModel(int initStart, Project initialProject) {
		progress = 0;
		int n = this.nIteration - initStart;
		for(int i = 0; i < n; i++) {
			projectList.remove(projectList.size()-1);
			summaryList.remove(summaryList.size()-1);
			emissionList.remove(emissionList.size()-1);
		}
		Project p = ProjectIO.generateSibling(initialProject);
		p.setLabel(mainProject.getLabel()+" #"+(initStart+1));
		
//		p.setUsingBelowgroundFactor(true);
//		p.setUsingModifiedFactor(true);
		//p.setIncludeBelowgroundEmission(false);
		//p.setIncludeModifiedEmission(false);
		
		//landcover objectnya udah beda!
		p = AbacusModel.runLanduseMatrixSimulation(p, 1, true);
		p = AbacusModel.updateTransitionProbabilityMatrix(p);
		projectList.add(p);
		summaryList.add(p.getSummary());
		for(int i = 1; i < n; i++) {
			p = ProjectIO.generateSibling(p);
			p = AbacusModel.runLanduseMatrixSimulation(p, 1, true);
			p = AbacusModel.updateTransitionProbabilityMatrix(p);
			p.setLabel(mainProject.getLabel()+" #"+(i+initStart+1));
			
//			p.setUsingBelowgroundFactor(true);
//			p.setUsingModifiedFactor(true);
			//p.setIncludeBelowgroundEmission(false);
			//p.setIncludeModifiedEmission(false);
						
			projectList.add(p);
			summaryList.add(p.getSummary());
			progress = (i+1)/(float)n;
		}
		updateThreshold(threshold);
		progress = 1;
	}

	public Project getSimulatedProject(int iteration) {
		if((iteration < 0)||(iteration > nIteration)) {
			return null;
		}
		return projectList.get(iteration);
	}
	
	public Summary getProjectSummary(int iteration) {
		return summaryList.get(iteration);
	}
	
	public Project getMainProject() {
		return mainProject;
	}
	
	public ModelProject(Project mainProject) {
		this.mainProject = mainProject;
	}

	public String getDescription() {
		return description ;
	}

	public String getLabel() {
		return label ;
	}

	public double getProgress() {
		return progress;
	}
	

}
